
package io.renren.common.utils;

import io.renren.common.exception.RRException;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;

/**
 * 日期处理
 */
public class DateUtils {
    /**
     * 时间格式(yyyy-MM-dd)
     */
    public final static String DATE_PATTERN = "yyyy-MM-dd";
    /**
     * 时间格式(yyyy-MM-dd HH:mm:ss)
     */
    public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param date 日期
     * @return 返回yyyy-MM-dd格式日期
     */
    public static String format(Date date) {
        return format(date, DATE_PATTERN);
    }

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param date    日期
     * @param pattern 格式，如：DateUtils.DATE_TIME_PATTERN
     * @return 返回yyyy-MM-dd格式日期
     */
    public static String format(Date date, String pattern) {
        if (date != null) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            return df.format(date);
        }
        return null;
    }

    /**
     * 字符串转换成日期
     *
     * @param strDate 日期字符串
     * @param pattern 日期的格式，如：DateUtils.DATE_TIME_PATTERN
     */
    public static Date stringToDate(String strDate, String pattern) {
        if (StringUtils.isBlank(strDate)) {
            return null;
        }

        DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
        return fmt.parseLocalDateTime(strDate).toDate();
    }

    /**
     * 根据周数，获取开始日期、结束日期
     *
     * @param week 周期  0本周，-1上周，-2上上周，1下周，2下下周
     * @return 返回date[0]开始日期、date[1]结束日期
     */
    public static Date[] getWeekStartAndEnd(int week) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusWeeks(week));

        date = date.dayOfWeek().withMinimumValue();
        Date beginDate = date.toDate();
        Date endDate = date.plusDays(6).toDate();
        return new Date[]{beginDate, endDate};
    }

    /**
     * 对日期的【秒】进行加/减
     *
     * @param date    日期
     * @param seconds 秒数，负数为减
     * @return 加/减几秒后的日期
     */
    public static Date addDateSeconds(Date date, int seconds) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusSeconds(seconds).toDate();
    }

    /**
     * 对日期的【分钟】进行加/减
     *
     * @param date    日期
     * @param minutes 分钟数，负数为减
     * @return 加/减几分钟后的日期
     */
    public static Date addDateMinutes(Date date, int minutes) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMinutes(minutes).toDate();
    }

    /**
     * 对当前日期的【分钟】进行加/减
     *
     * @param minutes 分钟数，负数为减
     * @return 加/减几分钟后的日期
     */
    public static Date addCurrDateMinutes(int minutes) {
        DateTime dateTime = new DateTime(new Date());
        return dateTime.plusMinutes(minutes).toDate();
    }

    /**
     * 对日期的【小时】进行加/减
     *
     * @param date  日期
     * @param hours 小时数，负数为减
     * @return 加/减几小时后的日期
     */
    public static Date addDateHours(Date date, int hours) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusHours(hours).toDate();
    }

    /**
     * 对日期的【天】进行加/减
     *
     * @param date 日期
     * @param days 天数，负数为减
     * @return 加/减几天后的日期
     */
    public static Date addDateDays(Date date, int days) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusDays(days).toDate();
    }


    /**
     * 对日期的【周】进行加/减
     *
     * @param date  日期
     * @param weeks 周数，负数为减
     * @return 加/减几周后的日期
     */
    public static Date addDateWeeks(Date date, int weeks) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusWeeks(weeks).toDate();
    }

    /**
     * 对日期的【月】进行加/减
     *
     * @param date   日期
     * @param months 月数，负数为减
     * @return 加/减几月后的日期
     */
    public static Date addDateMonths(Date date, int months) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMonths(months).toDate();
    }

    /**
     * 对日期的【年】进行加/减
     *
     * @param date  日期
     * @param years 年数，负数为减
     * @return 加/减几年后的日期
     */
    public static Date addDateYears(Date date, int years) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusYears(years).toDate();
    }

    /**
     * 放入一个时间段 得到这个时间区间列表
     * in:2016-10-12 2016-10-15
     * out:2016-10-12   2016-10-13   2016-10-14   2016-10-14
     *
     * @param startTime
     * @param endTime
     * @return
     * @throws Exception
     */
    public static List<String> getDateList(String startTime, String endTime)  {
        String[] starArr = startTime.split("-");//2016-10-12
        String[] endArr = endTime.split("-");//2016-10-12
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        start.set(Integer.parseInt(starArr[0]), Integer.parseInt(starArr[1]) - 1, Integer.parseInt(starArr[2]));
        Long startTIme = start.getTimeInMillis();
        end.set(Integer.parseInt(endArr[0]), Integer.parseInt(endArr[1]) - 1, Integer.parseInt(endArr[2]));
        Long endDate = end.getTimeInMillis();
        Long oneDay = 1000 * 60 * 60 * 24l;
        Long time = startTIme;
        List<String> dateList = new ArrayList<>();
        while (time <= endDate) {
            Date d = new Date(time);
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            dateList.add(df.format(d));
            time += oneDay;
        }
        return dateList;
    }

    /**
     * 传入的时间 加多少天之后是日期是多少
     * 比如传入2017-10-12  传入参数5  返回2017-10-17
     *
     * @return
     */
    public static String CurrDateAddDay(String curr, int day) {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        try {

            Date    dd = fmt.parse(curr);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(dd);
            calendar.add(Calendar.DATE, day);
            String rs = fmt.format(calendar.getTime());
            return rs;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return "";

    }

    /**
     * 传入的时间 jian多少天之后是日期是多少
     * 比如传入2017-10-12  传入参数5  返回2017-10-17
     *
     * @return
     */
    public static String CurrDateJianDay(String curr, int day) {
        try {
            SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
            Date dd = fmt.parse(curr);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(dd);
            calendar.add(Calendar.DATE, -day);
            String rs = fmt.format(calendar.getTime());

            return rs;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RRException("日期处理出错");
        }
    }

    /**
     * 获取当前月第一天
     *
     * @return
     */
    public static String getCurrFirstDay() {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            //获取当前月第一天：
            Calendar c = Calendar.getInstance();
            c.add(Calendar.MONTH, 0);
            c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
            String first = format.format(c.getTime());
            return first;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RRException("日期处理出错");
        }
    }

    /**
     * 获取某年的每一个月的开始日期和结束日期
     *
     * @return
     */
    public static List<Map<String, String>> getYearAllMonth(int year) {
        List<Map<String, String>> list = new ArrayList<>();
        try {

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            for (int i = 1; i <= 12; i++) {
                Map<String, String> item = new HashMap<>();
                YearMonth yearMonth = YearMonth.of(year, i);
                java.time.LocalDate localDate = yearMonth.atDay(1);
                LocalDateTime startOfDay = localDate.atStartOfDay();
                ZonedDateTime zonedDateTime = startOfDay.atZone(ZoneId.of("Asia/Shanghai"));

                item.put("sTime", sdf.format(Date.from(zonedDateTime.toInstant())));

                java.time.LocalDate endOfMonth1 = yearMonth.atEndOfMonth();
                LocalDateTime localDateTime1 = endOfMonth1.atTime(23, 59, 59, 999);
                ZonedDateTime zonedDateTime1 = localDateTime1.atZone(ZoneId.of("Asia/Shanghai"));
                String endTime = sdf.format(Date.from(zonedDateTime1.toInstant()));

                item.put("month", year + "年" + i + "月");
                if (new Date().before(sdf.parse(endTime))) {
                    item.put("eTime", sdf.format(new Date()));
                    list.add(item);
                    break;

                } else {
                    item.put("eTime", endTime);
                    list.add(item);
                }




            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new RRException("日期处理出错");
        }
        return list;
    }

    /**
     * 获取某年的每一个周的开始日期和结束日期
     *
     * @return
     */
    public static List<Map<String, String>> getYearAllWeek(int year) {
        List<Map<String, String>> list = new ArrayList<>();
        try {

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            for (int i = 1; i <= 52; i++) {
                Map<String, String> map = new HashMap<>(16);
                map.put("week", year+"第" + i + "周");

                map.put("sTime", sdf.format(sdf.parse(getStartDayOfWeekNo(year, i))));
                String endTime = sdf.format(sdf.parse(getEndDayOfWeekNo(year, i)));

                if (new Date().before(sdf.parse(endTime))) {

                    map.put("eTime", sdf.format(new Date()));

                    list.add(map);
                    break;
                } else {
                    map.put("eTime", endTime);
                    list.add(map);
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new RRException("日期处理出错");
        }
        return list;
    }

    /**
     * get first date of given month and year
     *
     * @param year
     * @param month
     * @return
     */
    public static String getFirstDayOfMonth(int year, int month) {
        String monthStr = month < 10 ? "0" + month : String.valueOf(month);
        return year + "-" + monthStr + "-" + "01";
    }

    /**
     * get the last date of given month and year
     *
     * @param year
     * @param month
     * @return
     */
    public static String getLastDayOfMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DATE, 1);
        calendar.add(Calendar.MONTH, 1);
        calendar.add(Calendar.DAY_OF_YEAR, -1);
        return calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH) + 1) + "-" +
                calendar.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * get Calendar of given year
     *
     * @param year
     * @return
     */
    private static Calendar getCalendarFormYear(int year) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        cal.set(Calendar.YEAR, year);
        return cal;
    }


    /**
     * get start date of given week no of a year
     *
     * @param year
     * @param weekNo
     * @return
     */
    public static String getStartDayOfWeekNo(int year, int weekNo) {
        Calendar cal = getCalendarFormYear(year);
        cal.set(Calendar.WEEK_OF_YEAR, weekNo);
        return cal.get(Calendar.YEAR) + "-" + (cal.get(Calendar.MONTH) + 1) + "-" +
                cal.get(Calendar.DAY_OF_MONTH);

    }

    /**
     * get the end day of given week no of a year.
     *
     * @param year
     * @param weekNo
     * @return
     */
    public static String getEndDayOfWeekNo(int year, int weekNo) {
        Calendar cal = getCalendarFormYear(year);
        cal.set(Calendar.WEEK_OF_YEAR, weekNo);
        cal.add(Calendar.DAY_OF_WEEK, 6);
        return cal.get(Calendar.YEAR) + "-" + (cal.get(Calendar.MONTH) + 1) + "-" +
                cal.get(Calendar.DAY_OF_MONTH);
    }



}
